#include "FileRepository_Test.h"

#include "server/file/FileRepository.h"
#include <Poco/File.h>
#include <iostream>
#include <stdexcept>
#include <string>
/*********************************************************/
std::string FileRepoTest::name()
{
	return("FileRepository");
}
/*********************************************************/
bool FileRepoTest::runUnitTests()
{
	bool result = true;

	if ( !repoCreationTest() ) result = false;
	if ( !dataRetrievalTest() ) result = false;
	if ( !reloadRepoTest() ) result = false;
	if ( !multipleChunkAddTest() ) result = false;
	if ( !archiveSizeTest() ) result = false;
	if ( !multipleArchiveTest() ) result = false;
	if ( !invalidChunkSizeTest() ) result = false;
	if ( !removeChunkTest() ) result = false;
	if ( !emptySlotTest() ) result = false;
	if ( !fileSizeUpdateTest() ) result = false;

	return( result ) ;
}
/*********************************************************/
bool FileRepoTest::fileSizeUpdateTest() 
{
	try {
		std::cout << "Running: fileSizeUpdateTest()";
		FileRepository		repo;
		repo.create("repo", 12, 200);
		repo.load("repo");
		repo.addChunk("test.zip", "Hello World!", 0, 12);
		unsigned long fileSize = repo.getFileSize("test.zip");
		repo.addChunk("test.zip", "Hello Worldz", 0, 24);
		if ( fileSize == repo.getFileSize("test.zip") ) {
			std::cout << "... failed! Filesize did not get updated!" << std::endl;
			return( false );
		}

		// Retry this with an unload + load
		repo.unload();
		repo.load("repo");
	
		if ( fileSize == repo.getFileSize("test.zip")) {
			std::cout << "... failed! Filesize did not get updated in index file after reloading the repository!" << std::endl;
			return( false );
		}

		repo.remove();

		std::cout << "... success!" << std::endl;
		return( true );
	} catch( std::exception& e) {
		std::cout << "... failed! with exception: " << e.what() << std::endl;
		return( false );
	}
}
/*********************************************************/
bool FileRepoTest::emptySlotTest()
{
	try {
		std::cout << "Running: emptySlotTest()";
		FileRepository		repo;
		repo.create("repo", 12, 200);
		repo.load("repo");
		repo.addChunk("test.zip", "Hello World!", 0, 12);
		unsigned long fileSize = 0;
		Poco::File	file("repo0.dat");
		fileSize = file.getSize();
		repo.remChunk("test.zip", 0, 12);
		if ( fileSize != file.getSize() ) {
			std::cout << "... failed! file size after removal not identical!" << std::endl;
			return false;
		}
		repo.addChunk("testje.dat", "Hello Worldz", 0, 12);
		if ( fileSize != file.getSize() ) {
			std::cout << "... failed! Class altered filesize after readdition of a chunk into an empty slot!";	
			return false;
		}
		std::cout << "... success!" << std::endl;
		return true;
	} catch( std::exception& e ) {
		std::cout << "... failed with exception: " << e.what() << std::endl;
		return ( false );
	}
}
/*********************************************************/
bool FileRepoTest::removeChunkTest()
{
	try {
		std::cout << "Running: removeChunkTest()";
		FileRepository		repo;
		repo.create("repo", 12, 200);
		repo.load("repo");
		repo.addChunk("test.txt", "Hello World!", 0, 12);
		repo.remChunk("test.txt", 0, 12);

		if ( !repo.available("test.txt", 0) ) {
			std::cout << "... success!" << std::endl;
			return( true );
		} else {
			std::cout << "... failed! Repository reported file still being available after removal" << std::endl;
			return( false );
		}
	} catch( std::exception& e) {
		std::cout << "... failed with exception: " << e.what() << std::endl;
		return( false );
	}
}
/*********************************************************/
bool FileRepoTest::invalidChunkSizeTest()
{
	try {
		std::cout << "Running: invalidChunkSizeTest()";
		FileRepository		repo;
		repo.create("repo", 10, 200);
		repo.load("repo");
		repo.addChunk("test.txt", "This chunk is to long for the chunk data limit!", 0, 20);

		std::cout << "... failed! expected exception... got none!" << std::endl;
		return( false );
	} catch( std::exception& e ) {
		std::string ex = e.what();
		std::string expected = "Invalid data size, expected length equal to chunkSize";
		if ( ex.compare(expected) == 0 ) {
			std::cout << "... success!" << std::endl;
			return( true );
		}
		std::cout << "... failed with exception: " << e.what() << std::endl;
		return( false );
	}
}
/*********************************************************/
bool FileRepoTest::multipleArchiveTest()
{
	try {
		std::cout << "Running: multipleArchiveTest()";
		FileRepository		repo;
		unsigned long chunkSize = 12;
		repo.create("repo", chunkSize, chunkSize+ARCHIVE_HEADER_SIZE+CHUNK_HEADER_SIZE);
		repo.load("repo");
		repo.addChunk("test.dat", "Hello World!", 0, 12);
		repo.addChunk("junk.dat", "Hello World2", 0, 12);

		// Check data for consistancy
		std::string data = repo.getChunk("test.dat", 0);	// Retrieve the data
		if ( data != "Hello World!" ) {
			std::cout << "... failed! Data not consistant! expected : Hello World! / Got: " << data << std::endl;
			return( false );
		}

		std::string data2 = repo.getChunk("junk.dat", 0);	// Retrieve the data
		if ( data2 != "Hello World2" ) {
			std::cout << "... failed! Data not consistant! expected: Hello World2 / Got: " << data2 << std::endl;
			return( false );
		}

		// Unload -> load & check again!
		repo.unload();
		repo.load("repo");

		// Check data for consistancy
		data = repo.getChunk("test.dat", 0);	// Retrieve the data
		if ( data != "Hello World!" ) {
			std::cout << "... failed! Data not consistant! expected: Hello World! / Got: " << data << std::endl;
			return( false );
		}

		data2 = repo.getChunk("junk.dat", 0);	// Retrieve the data
		if ( data2 != "Hello World2" ) {
			std::cout << "... failed! Data not consistant! expected: Hello World2 / Got: " << data2 << std::endl;
			return( false );
		}

		repo.remove();

		std::cout << "... success!" << std::endl;
		return( true );
	} catch(std::exception& e) {
		std::cout << "... failed with exception: " << e.what()  << std::endl;
		return( false);
	}
}
/*********************************************************/
bool FileRepoTest::archiveSizeTest()
{
	try {
		std::cout << "Running: archiveSizeTest()";
		FileRepository		repo;
		repo.create("repo", 150, 163);

		std::cout << "... failed! expected exception... got none!" << std::endl;
		return( false );
	} catch( std::exception& e ) {
		std::string ex = e.what();
		std::string expected = "Invalid repository settings: Can't store one chunk in an archive!";
		if ( ex.compare(expected) == 0 ) {
			std::cout << "... success!" << std::endl;
			return( true );
		}
		std::cout << "... failed with exception: " << e.what() << std::endl;
		return( false );
	}
}
/*********************************************************/
bool FileRepoTest::multipleChunkAddTest()
{
	try {
		std::cout << "Running: multipleChunkAddTest()";
		FileRepository		repo;
		repo.create("repo", 12, 600);
		repo.load("repo");
		repo.addChunk("test.txt", "Hello World!", 0, 12);
		repo.addChunk("junk.txt", "GIEFS MONEYZ", 0, 12);
		repo.addChunk("test.txt", "Hello World2", 1, 24);

		// Check data for consistancy
		std::string data = repo.getChunk("test.txt", 0);	// Retrieve the data
		if ( data != "Hello World!" ) {
			std::cout << "... failed! Data not consistant! expected: Hello World! / Got: " << data << std::endl;
			return( false );
		}

		std::string data2 = repo.getChunk("test.txt", 1);	// Retrieve the data
		if ( data2 != "Hello World2" ) {
			std::cout << "... failed! Data not consistant! expected: Hello World2 / Got: " << data2 << std::endl;
			return( false );
		}

		std::string data3 = repo.getChunk("junk.txt", 0);	// Retrieve the data
		if ( data3 != "GIEFS MONEYZ" ) {
			std::cout << "... failed! Data inconsistant! expected: 'GIEFS MONEYZ' / Got: '" << data3  << "'" << std::endl;
			return( false );
		}

		// Unload the repo & check for consistancy again!
		repo.unload();
		repo.load("repo");
	
		// Check data for consistancy
		data = repo.getChunk("test.txt", 0);	// Retrieve the data
		if ( data != "Hello World!" ) {
			std::cout << "... failed! Data not consistant! expected: Hello World! / Got: " << data << std::endl;
			return( false );
		}

		data2 = repo.getChunk("test.txt", 1);	// Retrieve the data
		if ( data2 != "Hello World2" ) {
			std::cout << "... failed! Data not consistant! expected: Hello World2 / Got: " << data2 << std::endl;
			return( false );
		}

		data3 = repo.getChunk("junk.txt", 0);	// Retrieve the data
		if ( data3 != "GIEFS MONEYZ" ) {
			std::cout << "... failed! Data not consistant! expected: 'GIEFS MONEYZ' / Got: '" << data3  << "'" << std::endl;
			return( false );
		}

		std::cout << "... success!" << std::endl;
		return( true );
	} catch( std::exception& e ) {
		std::cout << "...failed with exception: " << e.what() << std::endl;
		return( false );
	} 
}
/*********************************************************/
bool FileRepoTest::reloadRepoTest()
{
	try {
		std::cout << "Running: reloadRepoTest()";
		FileRepository		repo;
		repo.create("repo", 12, 600);
		repo.load("repo");
		repo.addChunk("test.txt", "Hello World!", 0, 12);
		repo.unload();

		repo.load("repo");
		std::string data = repo.getChunk("test.txt", 0);	// Retrieve the data
		if ( data != "Hello World!" ) {
			std::cout << "... failed! Data not consistant!" << std::endl;
			return( false );
		}
		
		std::cout << "... success!" << std::endl;
		return( true );
	} catch( std::exception& e ) {
		std::cout << "...failed with exception: " << e.what() << std::endl;
		return( false );
	} 
}
/*********************************************************/
bool FileRepoTest::repoCreationTest()
{
	std::cout << "Running: repoCreationTest()";

	FileRepository		repo;
	repo.create("repo", 12, 600);		// Create repository named "repo.ind" with a chunk size of 12 and max archive size of 600

	// This should create 2 files: repo.ind & repo0.dat
	if ( !Poco::File("repo.ind").exists()) {
		std::cout << "... failed! Repository index file was not created!" << std::endl;
		return( false );
	}

	std::cout << "... success!" << std::endl;
	return( true );
}
/*********************************************************/
bool FileRepoTest::dataRetrievalTest()
{
	std::cout << "Running: dataRetrievalTest()" ;

	try {
		FileRepository 		repo;
		repo.create("repo", 12, 600);			// Create a new repository
		repo.load("repo");
		repo.addChunk("test.txt", "Hello World!", 0, 12);	// Add a chunk of a file to the repository

		std::string data = repo.getChunk("test.txt", 0);	// Retrieve the data
		if ( data != "Hello World!" ) {
			std::cout << "... failed! Data not consistant!" << std::endl;
			return( false );
		}

		std::cout << "... success!" << std::endl;
		return( true );
	} catch( std::exception& e ) {
		std::cout << "... Exception: " << e.what() << std::endl;
		return( false );
	}
}
